﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using JiveMessenger.Utilities;
using System.Diagnostics;
using System.Windows.Input;
using System.Collections.ObjectModel;
using JiveMessenger.ViewModels;
using Windows.ApplicationModel;

// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236

namespace JiveMessenger.CustomControls
{
    public sealed partial class TabsControl : UserControl
    {

        private Canvas _pinAndTrashContainer;
        private Image _pinTabImage;
        private Image _removeTabImage;
        private bool _crossedPinThreshold;
        private bool _crossedDeleteThreshold;
        private bool _deleteFlickOccured;
        private bool _pinFlickOccured;
        private static double FLICK_VELOCITY = 1.5;



        public static readonly DependencyProperty CloseTabCommandProperty =
    DependencyProperty.Register(
        "CloseTabCommand",
        typeof(ICommand),
        typeof(TabsControl), new PropertyMetadata(null));

        public ICommand CloseTabCommand
        {
            get { return (ICommand)GetValue(CloseTabCommandProperty); }
            set { SetValue(CloseTabCommandProperty, value); }
        }

        public static readonly DependencyProperty PinTabCommandProperty =
        DependencyProperty.Register(
        "PinTabCommand",
        typeof(ICommand),
        typeof(TabsControl), new PropertyMetadata(null));

        public ICommand PinTabCommand
        {
            get { return (ICommand)GetValue(PinTabCommandProperty); }
            set { SetValue(PinTabCommandProperty, value); }
        }

        public static readonly DependencyProperty OpenTabCommandProperty =
        DependencyProperty.Register(
        "OpenTabCommand",
        typeof(ICommand),
        typeof(TabsControl), new PropertyMetadata(null));

        public ICommand OpenTabCommand
        {
            get { return (ICommand)GetValue(OpenTabCommandProperty); }
            set { SetValue(OpenTabCommandProperty, value); }
        }

        public static readonly DependencyProperty CloseTabListCommandProperty =
DependencyProperty.Register(
"CloseTabListCommand",
typeof(ICommand),
typeof(TabsControl), new PropertyMetadata(null));

        public ICommand CloseTabListCommand
        {
            get { return (ICommand)GetValue(CloseTabListCommandProperty); }
            set { SetValue(CloseTabListCommandProperty, value); }
        }


        public ObservableCollection<ViewModelTab> TabList
        {
            get { return (ObservableCollection<ViewModelTab>)GetValue(TabListProperty); }
            set { SetValue(TabListProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TabList.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TabListProperty =
            DependencyProperty.Register("TabList", typeof(ObservableCollection<ViewModelTab>), typeof(TabsControl), new PropertyMetadata(null, TabListCallback));

        private static void TabListCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }


        public TabsControl()
        {
            this.InitializeComponent();
            this.DataContext = this;
        }


        private void TabItem_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
        {

            // initialize the drag
            FrameworkElement fe = sender as FrameworkElement;
            fe.SetHorizontalOffset(0);
            _pinFlickOccured = false;
            _deleteFlickOccured = false;
            _crossedPinThreshold = false;
            var descendants = fe.Descendants();
            // find the container for the pin and trash graphics
            _pinAndTrashContainer = descendants
                                       .OfType<Canvas>()
                                       .Single(i => i.Name == "PinAndTrash");
            _pinTabImage = descendants
                                .OfType<Image>()
                                .Single(i => i.Name == "PinTabImage");

            _removeTabImage = descendants
                                .OfType<Image>()
                                .Single(i => i.Name == "RemoveTabImage");

            _pinTabImage.Source = new BitmapImage(new Uri("ms-appx:///Assets/Pinned_Down_White.png"));
            _removeTabImage.Source = new BitmapImage(new Uri("ms-appx:///Assets/AppBar/ApplicationBar.Delete.White.png"));

        }


        private void TabItem_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            FrameworkElement fe = sender as FrameworkElement;
            double offset = fe.GetHorizontalOffset().Value + e.Delta.Translation.X;
            fe.SetHorizontalOffset(offset);
            _pinFlickOccured = false;
            _deleteFlickOccured = false;

            if (e.Velocities.Linear.X < -FLICK_VELOCITY && !_deleteFlickOccured)
            {
                _deleteFlickOccured = true;
                Debug.WriteLine("Flicked item to delete");
            }
            else if (e.Velocities.Linear.X > FLICK_VELOCITY && !_pinFlickOccured)
            {
                _pinFlickOccured = true;

                Debug.WriteLine("Flicked item to pin");
            }

            _pinAndTrashContainer.Opacity = PinAndTrashOpacity(offset);


            if ((e.Cumulative.Translation.X > fe.ActualWidth / 2.5 || _pinFlickOccured))
            {
                if (!_crossedPinThreshold)
                {
                    _pinTabImage.Source = new BitmapImage(new Uri("ms-appx:///Assets/Pinned_Down_Green.png"));
                    _crossedPinThreshold = true;
                }
            }
            else if ((e.Cumulative.Translation.X < -fe.ActualWidth / 2.5 || _deleteFlickOccured))
            {
                if (!_crossedDeleteThreshold)
                {
                    _removeTabImage.Source = new BitmapImage(new Uri("ms-appx:///Assets/AppBar/ApplicationBar.Delete.Red.png"));
                    _crossedDeleteThreshold = true;
                }
            }
            else if (_crossedPinThreshold || _crossedDeleteThreshold)
            {
                _pinTabImage.Source = new BitmapImage(new Uri("ms-appx:///Assets/Pinned_Down_White.png"));
                _removeTabImage.Source = new BitmapImage(new Uri("ms-appx:///Assets/AppBar/ApplicationBar.Delete.White.png"));
                _crossedPinThreshold = false;
                _crossedDeleteThreshold = false;
            }

            e.Handled = true;
        }

        private void Grid_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
        {
            FrameworkElement fe = sender as FrameworkElement;
            if (_crossedDeleteThreshold || _crossedPinThreshold)
            {
                if (_crossedDeleteThreshold || _deleteFlickOccured)
                {
                    TabItemDeletedAction(fe);
                }
                else
                {
                    TabItemCompletedAction(fe);
                }
            }
            else
            {
                TabItemBounceBack(fe);
            }

        }
        private void TabItemDeletedAction(FrameworkElement deletedElement)
        {
            // _deleteSound.Play();

            var trans = deletedElement.GetHorizontalOffset().Transform;
            trans.Animate(trans.X, -(deletedElement.ActualWidth + 70),
                          "TranslateTransform.X", 300, 0, FillBehavior.HoldEnd, new SineEase()
                          {
                              EasingMode = EasingMode.EaseOut
                          },
            () =>
            {
                // find the model object that was deleted
                deletedElement.Opacity = 0;
                if (CloseTabCommand != null)
                    CloseTabCommand.Execute(deletedElement.DataContext);

                _deleteFlickOccured = false;
                deletedElement.RenderTransform = new CompositeTransform();
            });
        }
        private void TabItemCompletedAction(FrameworkElement fe)
        {
            // set the ToDoItem to complete
            if (PinTabCommand != null)
                PinTabCommand.Execute(fe.DataContext);
            // bounce back into place
            TabItemBounceBack(fe);
        }
        private void TabItemBounceBack(FrameworkElement fe)
        {
            var trans = fe.GetHorizontalOffset().Transform;
            
            string propertyPath = "TranslateTransform.X";
            trans.Animate(trans.X, 0, propertyPath, 300, 0, FillBehavior.HoldEnd, new BounceEase()
            {
                Bounciness = 5,
                Bounces = 2
            }, () =>
            {
                fe.Tag = null;
            });
        }
        private double PinAndTrashOpacity(double offset)
        {
            offset = Math.Abs(offset);
            if (offset < 50)
                return 0;

            offset -= 50;
            double opacity = offset / 100;

            opacity = Math.Max(Math.Min(opacity, 1), 0);
            return opacity;
        }

        private void MenuPathGrid_Tapped(object sender, TappedRoutedEventArgs e)
        {
            Grid grid = (Grid)sender;
            if (CloseTabCommand != null)
                CloseTabCommand.Execute(grid.DataContext);
        }

        private void TabNameGrid_Tapped(object sender, TappedRoutedEventArgs e)
        {
            Grid grid = (Grid)sender;
            if (OpenTabCommand != null)
                OpenTabCommand.Execute(grid.DataContext);
        }

        private void Grid_Tapped(object sender, TappedRoutedEventArgs e)
        {
            if (CloseTabListCommand != null)
                CloseTabListCommand.Execute(null);
        }
    }
}
